using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace JBORPG.Net
{
    public class ClientHolder
    {
        private TcpClient m_Client;
        private Thread m_Thread;
        private Server m_Server;

        public ClientHolder(Server server)
        {
            m_Server = server;
            m_Thread = new Thread(new ThreadStart(ReceiveLoop));
        }

        public TcpClient Client
        {
            get
            {
                return m_Client;
            }
            set
            {
                m_Client = value;
            }
        }

        public void Start()
        {
            m_Thread = new Thread(new ThreadStart(ReceiveLoop));
            m_Thread.Start();
        }

        public void Stop()
        {
            m_Thread.Abort();
            if (m_Client.Connected)
            {
                m_Client.Close();
            }
            m_Client = null;
        }

        public void ReceiveLoop()
        {
            try
            {
                while (true)
                {
                    if (!m_Client.Connected)
                    {
                        m_Thread.Abort();
                        break;
                    }

                    Byte[] buffer = new Byte[m_Client.Client.ReceiveBufferSize];
                    Int32 bytes = m_Client.Client.Receive(buffer);

                    if (bytes != 0)
                    {
                        m_Server.DataReceived(buffer, m_Client);
                    }
                }
            }
            catch
            {
                if (m_Client.Connected)
                    ReceiveLoop();
                else
                    this.Stop();
            }
        }
    }

    public class Server
    {
        private TcpListener m_Listener;
        private List<ClientHolder> m_Clients;
        private NetHandler m_NetHandler;

        public Server(NetHandler nh, IPAddress ia, Int32 port)
        {
            m_Listener = new TcpListener(ia, port);
            m_Clients = new List<ClientHolder>();
            m_NetHandler = nh;
        }

        public Server(NetHandler nh, Int32 port) : this(nh, IPAddress.Any, port){ }

        public void Listen()
        {
            m_Listener.Start();

            m_Listener.BeginAcceptTcpClient(new AsyncCallback(OnConnect), null);
        }

        private ClientHolder GetFreeClient()
        {
            foreach (ClientHolder ch in m_Clients)
            {
                if (ch.Client == null || ch.Client.Connected == false)
                    return m_Clients[m_Clients.IndexOf(ch)];
            }

            m_Clients.Add(new ClientHolder(this));
            return m_Clients[m_Clients.Count - 1];
        }

        private void OnConnect(IAsyncResult result)
        {
            ClientHolder ch = GetFreeClient();
            ch.Client = m_Listener.EndAcceptTcpClient(result);

            ch.Start();
            m_Listener.BeginAcceptTcpClient(new AsyncCallback(OnConnect), null);
        }

        private void CleanUp()
        {
            foreach (ClientHolder ch in m_Clients)
            {
                if (ch.Client.Connected == false)
                    m_Clients[m_Clients.IndexOf(ch)].Stop();
            }
        }

        public void DataReceived(Byte[] b, TcpClient client)
        {
            client.Client.Send(m_NetHandler.HandleData(b));
        }
    }
}
